package com.zhihao.trigger.job;

import com.xxl.job.core.handler.annotation.XxlJob;
import com.zhihao.domain.activity.model.valobj.ActivitySkuStockKeyVO;
import com.zhihao.domain.activity.service.IRaffleActivitySkuStockService;
import io.micrometer.core.annotation.Timed;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Jackson
 * @create 2025/3/21 14:32
 * @description
 *        redis延迟队列
 *          sku活动扣减库存 redis扣减库存同步mysql数据库 轮询从延迟队列中获取event并消费
 */
@Slf4j
@Component
public class UpdateActivitySkuStockJob {

    @Resource
    private IRaffleActivitySkuStockService skuStock;

    @Resource
    private ThreadPoolExecutor executor;

    /*
    @Qualifier 是用于解决多个同类型 Bean 的歧义性的注解。
    当 Spring 容器中存在多个相同类型的 Bean 时，直接使用 @Autowired 会抛出 NoUniqueBeanDefinitionException（因为无法确定要注入哪一个）。
    通过 @Qualifier("beanName") 可以指定要注入的 Bean 的名称，这里的 "redisson" 是 Bean 的唯一标识符。
     */
//    @Qualifier("redisson")
//    @Autowired
    @Resource
    private RedissonClient redisson;

    /**
     *  redis-活动不同sku库存扣减“Redis延迟队列”消息mq -> mq监听队列信息实现mysql数据库库存扣减同步
     *
     * @author Jackson
     * @date 2025-04-09 22:05
     **/
    @Timed(value = "UpdateActivitySkuStockJob", description = "更新活动sku库存任务")
    @XxlJob("UpdateActivitySkuStockJob")
    public void skuActivityStockSubConsumer() {
        RLock lock = redisson.getLock("big-market-UpdateActivitySkuStockJob");
        boolean isLocked = false;

        try {
            isLocked = lock.tryLock(3, 0, TimeUnit.SECONDS);
            if (!isLocked) return;
//            log.info("定时任务，更新sku活动消耗库存【延迟队列获取，降低对数据库的更新频次，不要产生竞争】");

            List<Long> skus = skuStock.querySkuList();
            for (Long sku : skus) {
                // 线程池 优化不同sku的mysql库存扣减行为
                executor.execute(()->{
                    ActivitySkuStockKeyVO activitySkuStockKeyVO = null;
                    try {
                        activitySkuStockKeyVO = skuStock.takeQueueValue(sku);
                    } catch (InterruptedException e) {
                        log.error("定时任务，更新活动sku库存失败 sku: {} topic: {}", sku, activitySkuStockKeyVO.getActivityId());
                    }
                    if (null == activitySkuStockKeyVO) return;  // null证明该sku库存扣减队列中暂时没有需要扣减的消息

                    log.info("定时任务，更新活动sku库存开始 sku:{} activityId:{}", activitySkuStockKeyVO.getSku(), activitySkuStockKeyVO.getActivityId());
                    skuStock.updateActivitySkuStock(activitySkuStockKeyVO.getSku());
                    log.info("定时任务，更新活动sku库存成功 sku:{} activityId:{}", activitySkuStockKeyVO.getSku(), activitySkuStockKeyVO.getActivityId());
                });
            }

        } catch (Exception e) {
            log.error("定时任务，更新sku活动消耗库存失败", e);
        }finally {
            if (isLocked){
                lock.unlock();
            }
        }
    }
}
